import { Label, tween, tweenUtil, Tween, director, Scheduler, macro, Vec3, Node, Vec2, v2, Mat4, v3, UITransform, Camera, isValid, Sprite, Color, sp } from "cc";
import { LogMgr } from "../manager/LogMgr";
import { PoolMgr } from "../manager/PoolMgr";
import { math } from "cc";

export class Utils {

    public static init() {


    }
    public static Format(src: string, ...any) {
        for (let i = 0; i < any.length; i++) {
            var reg = new RegExp("\\{" + i + "\\}", "gm");
            src = src.replace(reg, arguments[i + 1]);
        }
        return src
    }

    public static encrypt(str, pwd): string {
        if (pwd == null || pwd.length <= 0) {
            //alert("Please enter a password with which to encrypt the message.");
            return null;
        }
        let prand: any = "";
        for (let i = 0; i < pwd.length; i++) {
            prand += pwd.charCodeAt(i).toString();
        }
        let sPos = Math.floor(prand.length / 5);
        let mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
        let incr = Math.ceil(pwd.length / 2);
        let modu = Math.pow(2, 31) - 1;
        if (mult < 2) {
            //alert("Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password.");
            return null;
        }
        let salt: any = Math.round(Math.random() * 1000000000) % 100000000;
        prand += salt;
        while (prand.length > 10) {
            prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString();
        }
        prand = (mult * prand + incr) % modu;
        let enc_chr: any = "";
        let enc_str: any = "";
        for (let i = 0; i < str.length; i++) {
            let temp = (str.charCodeAt(i) ^ Math.floor((prand / modu) * 255)) + ""
            enc_chr = parseInt(temp);
            if (enc_chr < 16) {
                enc_str += "0" + enc_chr.toString(16);
            } else enc_str += enc_chr.toString(16);
            prand = (mult * prand + incr) % modu;
        }
        salt = salt.toString(16);
        while (salt.length < 8) salt = "0" + salt;
        enc_str += salt;
        return enc_str;
    }
    public static decrypt(str, pwd): string {
        if (str == null || str.length < 8) {
            //alert("A salt value could not be extracted from the encrypted message because it's length is too short. The message cannot be decrypted.");
            return;
        }
        if (pwd == null || pwd.length <= 0) {
            //alert("Please enter a password with which to decrypt the message.");
            return;
        }
        let prand: any = "";
        for (let i = 0; i < pwd.length; i++) {
            prand += pwd.charCodeAt(i).toString();
        }
        let sPos = Math.floor(prand.length / 5);
        let mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5));
        let incr = Math.round(pwd.length / 2);
        let modu = Math.pow(2, 31) - 1;
        let salt = parseInt(str.substring(str.length - 8, str.length), 16);
        str = str.substring(0, str.length - 8);
        prand += salt;
        while (prand.length > 10) {
            prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString();
        }
        prand = (mult * prand + incr) % modu;
        let enc_chr: any = "";
        let enc_str: any = "";
        for (let i = 0; i < str.length; i += 2) {
            enc_chr = parseInt((parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255)) + "");
            enc_str += String.fromCharCode(enc_chr);
            prand = (mult * prand + incr) % modu;
        }
        return enc_str;
    }
    /**
       * 产生随机整数，包含下限值，但不包括上限值
       * @param {Number} lower 下限
       * @param {Number} upper 上限
       * @return {Number} 返回在下限到上限之间的一个随机整数
       */
    public static randomRang(minNum: number, maxNum: number) {
        return Math.floor(Math.random() * (maxNum - minNum)) + minNum;
    }
    public static randomRang2(lower: number, upper: number) {
        return Math.floor(Math.random() * (upper - lower + 1)) + lower;
    }
    public static formatGold(num): string {
        let str = (num + '').replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, '$1,');

        return str
    }
    /**直接拷贝属性 */
    public static clonObj<T>(obj: T): T {
        var newObj = (obj instanceof Array ? [] : {}) as T;
        for (var key in obj) {
            var val = obj[key];

            //newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; //arguments.callee 在哪一个函数中运行，它就代表哪个函数, 一般用在匿名函数中。
            newObj[key] = typeof val === 'object' ? this.clonObj(val) : val;
        }
        return newObj;
    }
    /**在一数组中随机几个不同的数字
     * 从0开始
     * len数组的长度
     */
    public static randomNumInArr(numArr: number[], num: number) {
        if (num <= 0) {
            return null;
        }
        let arr = [];
        for (let i = 0; i < numArr.length; i++) {
            let random = Math.floor(Math.random() * (numArr.length - 1))
            let num1 = numArr[random];
            if (arr.indexOf(num1) == -1) {
                arr.push(num1)
            }
            if (arr.length == num) {
                return arr;
            }
        }
        return arr;
    }

    /**
    *  产生指定范围不重复的随机数(对数组随机排序思路)
    *  参数一: 最小值    int
    *  参数二: 最大值    int
    *  参数三: 随机数量  int
    *  返回值: 结果数组  Array
    **/
    public static getRandNumForRangeN(least: number, max: number, num: number): number[] {
        // 检查传值是否合法
        if (num > max - least) return [];
        // 产生指定范围的所有数值
        var numList = [];
        for (var i = least; i < max; i++) {
            numList.push(i);
        }
        // 对数组随机排序
        numList.sort(function () { return Math.random() < 0.5 ? -1 : 1 });
        // 返回前N个值
        return numList.slice(0, num);
    }
    static randomShort(arr: any[]): any[] {
        if (arr == null || arr.length <= 0) {
            return arr;
        }
        // 对数组随机排序
        arr.sort(function () {
            return Math.random() < 0.5 ? -1 : 1
        }
        );
        return arr;
    }
    /**
     *  产生指定数组不重复的随机数(对数组随机排序思路)
     *  参数一: 抽取数组  Array
     *  参数二: 随机数量  int
     *  返回值: 结果数组  Array
     **/
    public static getRandNumForArrayN(numArray: any[], num: number): any[] {
        // 检查传值是否合法
        if (num > numArray.length) return [];
        // 对数组随机排序
        numArray.sort(function () { return Math.random() < 0.5 ? -1 : 1 });
        // 返回前N个值
        return numArray.slice(0, num);
    }
    /**
       *  产生指定数组不重复的随机数(对数组随机排序思路)
       *  参数一: 抽取数组  Array
       *  参数二: 排除数值  Array
       *  参数三: 随机数量  int
       *  返回值: 结果数组  Array
       **/
    public static getRandNum2ForArrayN(numArray: any[], num2Array: any[], num: number): any[] {
        // 检查传值是否合法
        if (num > numArray.length) return [];
        // 对数组随机排序
        numArray.sort(function () { return Math.random() < 0.5 ? -1 : 1 });
        for (let i = 0; i < numArray.length; i++) {
            let ar = numArray[i]
            for (let j = 0; j < num2Array.length; j++) {
                let ar1 = num2Array[j]
                if (ar.id == ar1.id) {
                    numArray.splice(i, 1)
                }
            }
        }
        // 返回前N个值
        let list = numArray.slice(0, num);

        return list;
    }
    /**文字标签控件滚动数字 */
    public static rollNumLabelAtlas(isAdd: boolean, label: Label, addNum: number, totalNum: number, callback: Function, times: number = 6) {
        let num: number = addNum
        let count: number = times * 10
        let total: number = 0;
        let cellNum: number = num / count + 1
        if (num <= count) {
            count = num;
            cellNum = 1;
        } else {
            count = count + 1;
        }
        let _increaseNum = function () {
            if (isAdd) {
                if (total != num) {
                    total = total + cellNum;
                    if (total > num) {
                        cellNum = cellNum - (total - num)
                        total = num
                    }
                    let curNum = Number(label.string)
                    let showNum = Math.floor(curNum + cellNum).toFixed(0) + ""
                    label.string = showNum;
                }
            } else {
                if (total != num) {
                    total = total + cellNum;
                    if (total > num) {
                        cellNum = 0
                        total = num
                    }
                    let curNum = Number(label.string)
                    if (curNum > totalNum) {
                        let showNum = Math.floor(curNum - cellNum).toFixed(0) + ""
                        label.string = showNum;
                    }

                }
            }

        }
        if (count > 0) {
            tween(label.node).call(() => {
                _increaseNum()
            }).delay(0.05).union().repeat(count).call(() => {
                callback()
            }).start();
        } else {
            callback()
        }
    }

    public static weightRandom(arr: any[]) {
        let random = -1;
        while (random < 0) {
            //计算总权重
            let sumWeight = 0;
            for (let i = 0; i < arr.length; i++) {
                sumWeight += arr[i].weight;
            }
            let randomNumber = Math.random()
            let d1 = 0;
            let d2 = 0;
            for (let i = 0; i < arr.length; i++) {
                d2 += arr[i].weight / sumWeight;
                if (i == 0) {
                    d1 = 0;
                } else {
                    d1 += arr[i - 1].weight / sumWeight
                }
                if (d1 <= randomNumber && randomNumber < d2) {
                    random = i;
                    break;
                }
            }
        }
        return arr[random]
    }

    /**单个权重随机 */
    public static weight_randSingle(weight: number) {
        if (weight <= 0) {
            return false;
        }
        if (weight >= 100) {
            return true;
        }
        let randomNum = Math.floor(Math.random() * 100);
        if (randomNum <= weight) {
            return true;
        }
        return false;
    }

    /**
    * js数组实现权重概率分配，支持数字比模式(支持2位小数)和百分比模式(不支持小数，最后一个元素多退少补)
    * @param Array arr js数组，参数类型[Object,Object,Object……]
    * @return Array 返回一个随机元素，概率为其weight/所有weight之和，参数类型Object
    * @author shuiguang
    */
    public static weight_rand(arr): any {
        //参数arr元素必须含有weight属性，参考如下所示
        //var arr=[{name:'1',weight:1.5},{name:'2',weight:2.5},{name:'3',weight:3.5}];
        //var arr=[{name:'1',weight:'15%'},{name:'2',weight:'25%'},{name:'3',weight:'35%'}];
        //求出最大公约数以计算缩小倍数，perMode为百分比模式
        var per;
        var maxNum = 0;
        var perMode = false;
        //自定义Math求最小公约数方法
        let gcd = function (a, b) {
            var min = Math.min(a, b);
            var max = Math.max(a, b);
            var result = 1;
            if (a === 0 || b === 0) {
                return max;
            }
            for (var i = min; i >= 1; i--) {
                if (min % i === 0 && max % i === 0) {
                    result = i;
                    break;
                }
            }
            return result;
        };
        if (arr == null || arr.length == 0) {
            return null;
        }
        //使用clone元素对象拷贝仍然会造成浪费，但是使用权重数组对应关系更省内存
        var weight_arr = new Array();
        for (let i = 0; i < arr.length; i++) {
            if ('undefined' != typeof (arr[i].weight)) {
                if (arr[i].weight.toString().indexOf('%') !== -1) {
                    per = Math.floor(arr[i].weight.toString().replace('%', ''));
                    perMode = true;
                } else {
                    per = Math.floor(arr[i].weight * 100);
                }
            } else {
                per = 0;
            }
            weight_arr[i] = per;
            maxNum = gcd(maxNum, per);
        }
        //数字比模式，3:5:7，其组成[0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2]
        //百分比模式，元素所占百分比为15%，25%，35%
        var index = new Array();
        var total = 0;
        var len = 0;
        if (perMode) {
            if (arr == null || arr.length == 0) {
                return
            }
            for (let i = 0; i < arr.length; i++) {
                //len表示存储arr下标的数据块长度，已优化至最小整数形式减小索引数组的长度
                len = weight_arr[i];
                for (let j = 0; j < len; j++) {
                    //超过100%跳出，后面的舍弃
                    if (total >= 100) {
                        break;
                    }
                    index.push(i);
                    total++;
                }
            }
            //使用最后一个元素补齐100%
            while (total < 100) {
                index.push(arr.length - 1);
                total++;
            }
        } else {
            for (let i = 0; i < arr.length; i++) {
                //len表示存储arr下标的数据块长度，已优化至最小整数形式减小索引数组的长度
                len = weight_arr[i] / maxNum;
                for (let j = 0; j < len; j++) {
                    index.push(i);
                }
                total += len;
            }
        }
        //随机数值，其值为0-11的整数，数据块根据权重分块
        var rand = Math.floor(Math.random() * total);
        //console.log(index);
        return arr[index[rand]];
    }

    public static stringFormat(src: string, ...any) {
        var s = arguments[0];
        for (var i = 0; i < arguments.length - 1; i++) {
            var reg = new RegExp("\\{" + i + "\\}", "gm");
            s = s.replace(reg, arguments[i + 1]);
        }
        return s;
    }

    public static scheduleOnce(func: Function, target: any, delayTime: number) {
        Scheduler.enableForTarget(target);
        director.getScheduler().schedule(func as any, target, 1, 0, delayTime, false)
    }
    public static unSchedule(func: Function, target: any) {
        director.getScheduler().unschedule(func, target)

    }
    public static schedule(func: Function, target: any, invertTime: number) {
        Scheduler.enableForTarget(target);
        director.getScheduler().schedule(func as any, target, invertTime, macro.REPEAT_FOREVER, 0, false)
    }

    /**
     * 随机生产不同的数组下标
     * @param len 数组的长度
     * @param max 需要生产几个id
     * @param arr 生产的id数组
     */
    public static randomDiffIndex(len: number, max: number, arr: number[]) {
        let idx = Utils.randomRang(0, len)
        if (this.checkExist(idx, arr)) {
            this.randomDiffIndex(len, max, arr)
        } else {
            arr.push(idx)
            if (arr.length < 3) {
                this.randomDiffIndex(len, max, arr);
            }
        }
    }
    private static checkExist(idx: number, arr: number[]): boolean {
        for (let i = 0; i < arr.length; i++) {
            let id = arr[i]
            if (id == idx) {
                return true;
            }
        }
        return false;
    }
    public static genUUID(): string {
        let S4: Function = () => {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }
        return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4());
    }
    public static bezier(C1, C2, C3, C4, t) {
        var t1 = 1 - t;
        return t1 * (t1 * (C1 + (C2 * 3 - C1) * t) + C3 * 3 * t * t) + C4 * t * t * t;
    }
    public static bezierTo(duration: number, node: Node, c1: Vec3, c2: Vec3, to: Vec3, cb: Function, opts?: any) {
        let c0x = c1.x, c0y = c1.y,
            c1x = c2.x, c1y = c2.y,
            c0z = c1.z, c1z = c2.z;
        opts = opts || Object.create(null);
        opts.progress = function (start, end, current, t) {
            LogMgr.getInstance().debug("cur: ", current)
            LogMgr.getInstance().debug("start: ", start)
            LogMgr.getInstance().debug("end: ", end)
            // current.x = Utils.bezier(start.x, c0x, c1x, end.x, t);
            // current.y = Utils.bezier(start.y, c0y, c1y, end.y, t);
            // current.z = Utils.bezier(start.z, c0z, c1z, end.z, t);
            return current;
        }
        tween(node).to(duration, { position: to }, opts).call(() => {
            if (cb) {
                cb();
            }
        }).start()
    }

    public static calcStringLenght(str: string): number {
        if (str == null) {
            str = "";
        }
        let regex = /<.+?\/?>/g;
        let matchArr = str.match(regex);
        if (matchArr) {
            for (let i = 0; i < matchArr.length; i++) {
                let st = matchArr[i]
                str = str.replace(st, "")
            }
        }

        let font_num = 0; //当前字数
        let char_num = 0; //当前字符数 2个字符 = 1个字 
        for (let i = 0; i < str.length; i++) {
            if (str[i].charCodeAt(0) >= 0 && str[i].charCodeAt(0) <= 127) {
                char_num++;
                if (char_num == 2) {
                    font_num++;
                    char_num = 0;
                }
            } else {
                font_num++;
            }
        }
        return font_num;
    }

    public static calcStringLine(str: string, length: number): string[] {
        if (str == null) {
            str = "";
        }
        if (length == null) {
            length = str.length;
        }
        let str_list: string[] = new Array();
        let cur_index = 0;
        let font_num = 0; //当前字数
        let char_num = 0; //当前字符数 2个字符 = 1个字 
        for (let i = 0; i < str.length; i++) {
            if (str[i].charCodeAt(0) >= 0 && str[i].charCodeAt(0) <= 127) {
                char_num++;
                if (char_num == 2) {
                    font_num++;
                    char_num = 0;
                }
            } else if (str[i] == '\n') {
                font_num = 0;
                str_list.push(str.substring(cur_index, i));
                cur_index = i + 1;
            } else {
                font_num++;
            }
            if (font_num == length) {
                font_num = 0;
                str_list.push(str.substring(cur_index, i + 1));
                cur_index = i + 1;
            }
        }
        if (cur_index < str.length) {
            str_list.push(str.substring(cur_index, str.length));
        }
        return str_list;
    }
    /**
   * 获取两点间的距离
   * @param p1 点1
   * @param p2 点2
   */
    public static getDistance(p1: Vec3, p2: Vec3): number {
        return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.z - p1.z, 2));
    }
    /**
     * 获取两点间的角度，利用特定指定周来计算角度,一般用于导弹计算，以导弹为主体
     * @param start 起始点
     * @param end 结束点
     * @param axis 指定轴
     */
    public static getAngleAxis(start: Vec3, end: Vec3, axis: Vec2) {
        let dx: number = end.x - start.x;
        let dy: number = end.z - start.z;
        // dy = Math.abs(dy);
        let dir: Vec2 = v2(dx, dy);
        let angle = dir.signAngle(axis);
        let degree = angle / Math.PI * 180;
        return degree;
    }

    /**
     * 利用角度计算sin值
     * @param degree 要计算的的角度值
     */
    public static angleToSin(degree: number) {
        return Math.sin((degree / 180) * Math.PI);
    }

    /**
     * 利用角度计算cos值
     * @param degree 要计算的的角度值
     */
    public static angleToCos(degree: number) {
        return Math.cos((degree / 180) * Math.PI);
    }


    /**坐标转换（UI节点转换） */
    public static changePosForUINode(curNode: Node, converNode: Node) {
        if (!isValid(curNode) || !isValid(converNode)) {
            return v3();
        }
        let tempPos = v3();
        let uiNodeTransform = converNode.getComponent(UITransform);
        uiNodeTransform.convertToNodeSpaceAR(curNode.worldPosition, tempPos);
        console.log("tempPos：", tempPos);
        return tempPos;
    }
    /**坐标转换（3D世界坐标） */
    public static changePosFor3DTo3D(curNode: Node, converNode: Node) {
        if (!isValid(curNode) || !isValid(converNode)) {
            return v3();
        }
        // let pos = curNode.getWorldPosition();
        // let pos1 = curNode;
        let tempPos = v3();
        let tempMat4 = new Mat4();
        Mat4.invert(tempMat4, converNode.getWorldMatrix());
        Vec3.transformMat4(tempPos, curNode.getWorldPosition(), tempMat4);
        // console.log("tempPos：", tempPos);
        return tempPos;
    }
    /**坐标转换（3D转屏幕坐标转ui坐标） */
    public static changePosFor3DToScreenToUI(camera3D: Camera, curNode: Node) {
        if (!isValid(curNode)) {
            return v3();
        }
        let sceenPoint = camera3D.worldToScreen(curNode.worldPosition);
        let uiPoint = camera3D.screenToWorld(sceenPoint);
        return uiPoint;
    }
    /**坐标转换（3D转ui坐标） */
    public static changePosFor3DToUI(camera3D: Camera, curNode: Node, uiNode: Node) {
        if (!isValid(curNode) || !isValid(uiNode)) {
            return v3();
        }
        let tempPos = v3();
        camera3D.convertToUINode(curNode.worldPosition, uiNode, tempPos);
        return tempPos;
    }
    /**字符串转换为字符数组 */
    public static getTabelArr(goodsStr: string): Array<string> {
        if (!goodsStr) {
            return [];
        }
        //console.log("物品配置：", goodsStr);
        let goodsArr = [];
        let str = "";
        let lenGoodsStr = goodsStr.length;
        for (let index = 0; index < lenGoodsStr; index++) {
            if (goodsStr[index] == "[") {
                continue;
            }
            else {
                if (goodsStr[index] == "," || goodsStr[index] == "]") {
                    if (str != "") goodsArr.push(str);
                    str = "";
                }
                else {
                    str += goodsStr[index];
                }
            }
        }
        return goodsArr;
    }

    /**字符数组转换为数字数组 */
    public static getNumArrForStrArr(strArr: Array<string>): Array<number> {
        let numArr = [];
        let lenStrArr = strArr.length;
        for (let index = 0; index < lenStrArr; index++) {
            numArr.push(Number(strArr[index]));
        }
        return numArr;
    }

    /**字符串转换为数字数组 字符串必须为数字类型 [1,2,3] */
    public static getNumArrForStr(goodsStr: string): Array<number> {
        let strArr = this.getTabelArr(goodsStr);
        let numArr = this.getNumArrForStrArr(strArr);
        return numArr;
    }

    /**字符串转换为字符数组 多维数组 */
    public static getTabelArrForMany(goodsStr: string): Array<Array<string>> {
        if (!goodsStr) {
            return [];
        }
        //console.log("物品配置：", goodsStr);
        let goodsArr = [];
        let strArr = [];
        let str = "";
        for (let index = 0; index < goodsStr.length; index++) {
            if (goodsStr[index] == "[") {
                continue;
            }
            else {
                if (goodsStr[index] == ",") {
                    if (str != "") strArr.push(str);
                    str = "";
                }
                else if (goodsStr[index] == "]") {
                    if (str != "") strArr.push(str);
                    str = "";
                    if (strArr.length > 0) goodsArr.push(strArr);
                    strArr = [];
                }
                else {
                    str += goodsStr[index];
                }
            }
        }
        return goodsArr;
    }

    /**字符数组转换为数字数组 多维 */
    public static getNumArrForStrArrForMany(strArr: Array<Array<string>>): Array<Array<number>> {
        let numArr = [];
        let lenStrArr = strArr.length;
        for (let index = 0; index < lenStrArr; index++) {
            let lenStrArr1 = strArr[index].length;
            let strArrCopy = [];
            for (let indexCopy = 0; indexCopy < lenStrArr1; indexCopy++) {
                strArrCopy.push(Number(strArr[index][indexCopy]));
            }
            numArr.push(strArrCopy);
        }
        return numArr;
    }

    /**字符串转换为数字数组 字符串必须为数字类型 多个[1,2],[1,6]或者[[1,2],[1,6]] */
    public static getNumArrForStrForMany(goodsStr: string): Array<Array<number>> {
        let strArr = this.getTabelArrForMany(goodsStr);
        let numArr = this.getNumArrForStrArrForMany(strArr);
        return numArr;
    }
    /**根据初始向量和方向向量 获取当前角度 */
    public static getAngleForStartVecAndDirVec(startVec: Vec2, dirVec: Vec3, is3D: boolean = false) {
        let dirVecZ = is3D ? -dirVec.z : dirVec.z;
        let angle = startVec.signAngle(v2(dirVec.x, dirVecZ)) * 180 / Math.PI;
        return v3(0, angle, 0);
    }

    /**加入对象池 */
    public static addToPool(key: string, node: Node) {
        if (!isValid(node)) {
            return;
        }
        PoolMgr.getInstance().freeNode(node.name, node);
    }

    /**
     * 设置透明度
     * @param spr 
     * @param isHalf 是否要半透明
     */

    public static setAlpha(spr: Sprite, isHalf: boolean) {
        return new Color(spr.color.r, spr.color.g, spr.color.b, isHalf == true ? 128 : 255)
    }
    /**
     * 
     * // 示例使用;
     * const original = {
     *     a: 1,
     *     b: [2, 3, { d: 4 }],
     *     c: { e: 5 }
     * };
     * 
     * const copied = deepClone(original);
     * console.log(copied);
     * 
     * @param obj 
     * @returns 
     */

    public static copyObj<T>(obj: T): T {
        // 检查是否为 null 或者不是对象
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }

        // 处理数组
        if (Array.isArray(obj)) {
            return obj.map(item => this.copyObj(item)) as unknown as T;
        }

        // 处理对象
        const clonedObj: { [key: string]: any } = {};
        for (const key in obj) {
            if (obj.hasOwnProperty(key)) {
                clonedObj[key] = this.copyObj(obj[key]);
            }
        }

        return clonedObj as T;
    }
    /**
       * 深度拷贝对象
       * @param obj 需要拷贝的对象
       * @returns 深拷贝后的新对象
       */
    public deepClone<T>(obj: T): T {
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }
        const clone: any = Array.isArray(obj) ? [] : {};
        for (const key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                clone[key] = this.deepClone(obj[key]);
            }
        }
        return clone as T;
    }
    /**
     * 获取重复id
     * @param reperatId 重复id
     * @param allObj1 所有id
     * @returns
     */
    public static getRepeatNew(reperatId, allObj1 = {}): IArr {
        let repeatArr: IArr = {}
        for (let k in allObj1) {
            allObj1[k] = allObj1[k] % 3
            if (allObj1[k] === 0) {
                delete allObj1[k]
            }
        }
        //记录花朵id
        let arr1 = [];
        let arr2 = []
        for (let k in allObj1) {
            for (let i = 0; i < allObj1[k]; i++) {
                if (k == reperatId) {
                    arr2.push(k)
                } else {
                    arr1.push(k)
                }
            }
        }
        if (arr1.length + arr2.length === 0) {
            console.log("无需处理")
            return repeatArr
        }
        if ((arr1.length + arr2.length) % 3 === 0) {
            var getReaData = function (arr1) {
                if (arr1.length < 3) {
                    arr1 = arr1.concat(arr2)
                    arr2 = []
                }
                let indexValue = arr1.shift();
                repeatArr[indexValue] = {
                    value: indexValue,
                    count: allObj1[indexValue],
                    repeatArr: []
                }
                repeatArr[indexValue].count += 1;
                repeatArr[indexValue].repeatArr.push(...arr1.splice(0, 2))
                if (arr1.length > 0) {
                    getReaData(arr1)
                }
            }
            getReaData(arr1)
            console.log("repeatArr", repeatArr, allObj1, arr2, arr1)
        } else {
            //这里做容错处理
            // let remainder = (arr1.length + arr2.length) % 3;
            // let lastKey = Object.keys(allObj1).pop();
            // if (lastKey) {
            //     allObj1[lastKey] += remainder;
            // }
            console.warn("错误，有些花朵数据都无法被3整除，需要做容错处理，理论上这里是不需要做处理的", reperatId, allObj1)
        }
        return repeatArr
    }


    // 生成随机数的函数
    private static getRandomBetween(min: number, max: number): number {
        return Math.random() * (max - min) + min;
    }
    /** 示例使用
        ** const startPoint: Point = { x: 0, y: 0 };
        ** const endPoint: Point = { x: 100, y: 100 };
        ** const controlPointOffset = 50; // 控制点的偏移量，影响轨迹的随机性
        ** const butterflyPath = generateButterflyPath(startPoint, endPoint, controlPointOffset);
        -  输出生成的路径
        ** console.log("蝴蝶飞行轨迹:", butterflyPath);
        ** 生成蝴蝶飞行轨迹的函数
    **/
    public static generateButterflyPath(start: Vec3, end: Vec3, controlPointOffset: number): Point[] {
        const controlPoint: Point = {
            x: this.getRandomBetween(start.x - controlPointOffset, end.x + controlPointOffset),
            y: this.getRandomBetween(start.y - controlPointOffset, end.y + controlPointOffset)
        };

        const path: Point[] = [];
        const steps = 100; // 控制路径的平滑度，步数越多越平滑

        for (let t = 0; t <= 1; t += 1 / steps) {
            const x = (1 - t) * (1 - t) * start.x + 2 * (1 - t) * t * controlPoint.x + t * t * end.x;
            const y = (1 - t) * (1 - t) * start.y + 2 * (1 - t) * t * controlPoint.y + t * t * end.y;
            path.push({ x, y });
        }

        return path;
    }
    /**
     * 从数组中随机取出不重复的值
     * @param {Array} arr - 输入数组
     * @param {number} count - 需要取出的数量
     * @returns {Array} - 随机取出的不重复值
     */

    public static getRandomUniqueValues(arr: number[], count: number) {
        if (count === 0) {
            return [];
        }
        // 如果需要的数量大于数组长度，返回整个数组
        if (count > arr.length) {
            return arr.slice(); // 返回数组的副本
        }

        // 创建一个 Set 来存储唯一值
        const uniqueValues = new Set();

        // 随机选择不重复的值
        while (uniqueValues.size < count) {
            const randomIndex = Math.floor(Math.random() * arr.length); // 生成随机索引
            uniqueValues.add(arr[randomIndex]); // 添加到 Set 中，自动去重
        }

        // 将 Set 转换为数组并返回
        return Array.from(uniqueValues) as number[];
    }
    public static skinConfig: ({
        skin1: string;
        skin2: string;
        type: number;
        price: number;
        skin?: undefined;
    } | {
        skin: string;
        type: number;
        price: number;
        skin1?: undefined;
        skin2?: undefined;
    })[][];
    // ... existing Utils class methods ...

    /**
     * 动态分配数值到数组
     * @param total 需要分配的总和
     * @param length 目标数组长度
     * @param maxAttempts 最大调整尝试次数（默认10次）
     * @returns 符合要求的数值数组
     */
    public static dynamicDistribution(total: number, length: number): number[] {
        const result = new Array(length).fill(0);
        
        while (total > 0) {
            let index = Math.floor(Math.random() * result.length);
            result[index] += 1;
            total--
        }
        return result;
    }
    public static  dynamicDistribution1(total: number, length: number, zeroProbability: number = 0.2): number[] {
        const result = new Array(length).fill(0);
        // 存储非零分配位置的索引
        let nonZeroIndices: number[] = [];
        for (let i = 0; i < length; i++) {
            if (Math.random() < zeroProbability) {
                result[i] = 0;
            } else {
                nonZeroIndices.push(i);
            }
        }
    
        let remainingTotal = total;
        while (remainingTotal > 0 && nonZeroIndices.length > 0) {
            let index = Math.floor(Math.random() * nonZeroIndices.length);
            let targetIndex = nonZeroIndices[index];
            result[targetIndex] += 1;
            remainingTotal--;
            // 如果该位置已经达到相对合理的值，可考虑移除该位置
            // 这里简单以值达到 5 为例，可根据实际情况调整
            if (result[targetIndex] >= 4) {
                nonZeroIndices.splice(index, 1);
            }
        }
        return result;
    }
    






}
interface IObj {
    value: number,
    count: number,
    repeatArr: number[]
}
interface IArr {
    [key: string]: IObj
}
// 定义一个点的接口
interface Point {
    x: number;
    y: number;
}